#include "BVH.h"


BVH::BVH(){
}


BVH::~BVH(){
}


bool BVH::build(Scene *_s, int _g){
	if (_s == NULL){
		return false;
	}
	theScene = _s;
	//initialize the root node
	root = BVHnode();
	//clear the shape lists
	theUnboundedShapes.clear();
	theShapes.clear();
	//copy the scene's shape pointers into the list
	int shapeCount = theScene->shapeCount();
	vector<Shape*>::iterator nextShape = theScene->shapes();
	for (int i = 0; i < shapeCount; i++){
		Shape* sh = *nextShape;
		if (sh->isBounded()){
			//printf("accelerated add shape\n");
			theShapes.push_back(*nextShape);
		}
		//don't add planes; they cannot fit inside a bounding box
		else{
			//printf("accelerated add plane\n");
			theUnboundedShapes.push_back(*nextShape);
		}
		
		nextShape++;
	}
	//pass a set of objects or indices to the root node and call its build function
	//return the result of that
	return root.build(theShapes, _g);
}

bool BVH::intersect(Intersection &_int){
	//these are for keeping track of the intersections between the ray and the bounding boxes
	float t0 = -1e30f;
	float t1 = 1e30f;
	//first check the list of planes
	list<Shape*>::iterator it;
	for (it = theUnboundedShapes.begin(); it != theUnboundedShapes.end(); it++){
		Shape* aPlane = *it;
		aPlane->intersect(_int);
	}
	//then check the BVH
	if (root.intersect(_int.ray(), t0, t1)){
		float the_t = (t0 < 0) ? t1 : t0;
		bool isInside = false;
		if (t0 < 0)isInside = true;
		//TODO: if the ray originates from inside a bounding box, you have to check everything inside
		if (the_t < _int.dist() || isInside)
			root.intersect(_int);
	}
	return _int.intersected();
}
